/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <flgrCoreDispatch.h>
#include <flgrCoreIO.h>
#include <flgrCoreMalloc.h>
#include <flgrCoreArithDef.h>
#include "flgrArithShift.h"
#include "flgrArithShiftFast.h"

/*!
 * \defgroup group_fulguro_arith_shift Shift Based Arithmetic
 * Shift Based Arithmetic
 * \ingroup group_fulguro_arith
 * @{
 */



#define FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(dtype,operator)	\
  int j,k;							\
  int spp = datdest->spp;					\
  int sfsize = spp*right_shift_size;				\
  dtype *psrc1 = (dtype*) data1->array;				\
  dtype *pdest = (dtype*) datdest->array;			\
  int length = datdest->length*spp;				\
  dtype v1;							\
  dtype v2;							\
  dtype result;							\
								\
  FLGR_DECLARE_FUNCTION;					\
  								\
  for(j=0 ; j<sfsize ; j++) {					\
    result = flgr_get_array_##dtype(psrc1,j);			\
    flgr_set_array_##dtype(pdest,j,result);			\
  }								\
								\
  for(j=sfsize,k=0 ; j<length ; j++,k++) {			\
    v1 = flgr_get_array_##dtype(psrc1,j);			\
    v2 = flgr_get_array_##dtype(psrc1,k);			\
    result = operator(v1,v2);					\
    flgr_set_array_##dtype(pdest,j,result);			\
  }								\
								\
  return


#define FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(dtype,operator)	\
  int j,k;							\
  int spp = datdest->spp;					\
  int sfsize = spp*left_shift_size;				\
  dtype *psrc1 = (dtype*) data1->array;				\
  dtype *pdest = (dtype*) datdest->array;			\
  int length = datdest->length*spp;				\
  dtype v1;							\
  dtype v2;							\
  dtype result;							\
								\
  FLGR_DECLARE_FUNCTION;					\
								\
  for(j=0,k=sfsize ; j<length-sfsize ; j++,k++) {		\
    v1 = flgr_get_array_##dtype(psrc1,j);			\
    v2 = flgr_get_array_##dtype(psrc1,k);			\
    result = operator(v1,v2);					\
    flgr_set_array_##dtype(pdest,j,result);			\
  }								\
								\
  for(j=length-sfsize ; j<length ; j++) {			\
    result = flgr_get_array_##dtype(psrc1,j);			\
    flgr_set_array_##dtype(pdest,j,result);			\
  }								\
								\
  return




void flgr1d_arith_sup_shift_right_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
  if((right_shift_size==1) &&(datdest->spp==1)) {
    flgr1d_arith_sup_shift_1_right_fast_fgBIT(datdest,data1);
  }else {
    FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgBIT,flgr_defop_sup_fgBIT);
  }
}
void flgr1d_arith_sup_shift_right_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
#if defined(__SSE2__) || defined(SSE)
  flgr1d_arith_sup_shift_right_fast_fgUINT8(datdest,data1,right_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgUINT8,flgr_defop_sup_fgUINT8); 
#endif
}
void flgr1d_arith_sup_shift_right_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgUINT16,flgr_defop_sup_fgUINT16); 
}
void flgr1d_arith_sup_shift_right_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgUINT32,flgr_defop_sup_fgUINT32); 
}
void flgr1d_arith_sup_shift_right_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgINT8,flgr_defop_sup_fgINT8); 
}
void flgr1d_arith_sup_shift_right_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
#if defined(__SSE2__) || defined(SSE)
  flgr1d_arith_sup_shift_right_fast_fgINT16(datdest,data1,right_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgINT16,flgr_defop_sup_fgINT16); 
#endif
}
void flgr1d_arith_sup_shift_right_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgINT32,flgr_defop_sup_fgINT32); 
}
void flgr1d_arith_sup_shift_right_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
#if defined(SSE)
  flgr1d_arith_sup_shift_right_fast_fgFLOAT32(datdest,data1,right_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgFLOAT32,flgr_defop_sup_fgFLOAT32); 
#endif
}
void flgr1d_arith_sup_shift_right_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
#if defined(__SSE2__)
  flgr1d_arith_sup_shift_right_fast_fgFLOAT64(datdest,data1,right_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgFLOAT64,flgr_defop_sup_fgFLOAT64); 
#endif
}

////////////////////////////////////////////////////////////////////////////
/*! Compute Sup between data1 and data1 shifted on the right by right_shift_size elements
 *  @param datdest : pointer to FLGR_Data1D
 *  @param data1 : pointer to FLGR_Data1D
 *  @param right_shift_size : integer
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_arith_sup_shift_right(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (data1==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(right_shift_size<0) {
    POST_ERROR("shift size must be > 0\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if((ret = flgr1d_is_data_same_attributes(datdest,data1,__FUNCTION__)) != FLGR_RET_OK) return ret;

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_arith_sup_shift_right,datdest,data1,right_shift_size);

}





void flgr1d_arith_sup_shift_left_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
  if((left_shift_size==1) &&(datdest->spp==1)) {
    flgr1d_arith_sup_shift_1_left_fast_fgBIT(datdest,data1);
  }else {
    FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgBIT,flgr_defop_sup_fgBIT);
  }
}
void flgr1d_arith_sup_shift_left_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
#if defined(__SSE2__) || defined(SSE)
  flgr1d_arith_sup_shift_left_fast_fgUINT8(datdest,data1,left_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgUINT8,flgr_defop_sup_fgUINT8);
#endif
}
void flgr1d_arith_sup_shift_left_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgUINT16,flgr_defop_sup_fgUINT16);
}
void flgr1d_arith_sup_shift_left_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgUINT32,flgr_defop_sup_fgUINT32);
}
void flgr1d_arith_sup_shift_left_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgINT8,flgr_defop_sup_fgINT8);
}
void flgr1d_arith_sup_shift_left_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
#if defined(__SSE2__) || defined(SSE)
  flgr1d_arith_sup_shift_left_fast_fgINT16(datdest,data1,left_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgINT16,flgr_defop_sup_fgINT16);
#endif
}
void flgr1d_arith_sup_shift_left_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgINT32,flgr_defop_sup_fgINT32);
}
void flgr1d_arith_sup_shift_left_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
#if defined(SSE)
  flgr1d_arith_sup_shift_left_fast_fgFLOAT32(datdest,data1,left_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgFLOAT32,flgr_defop_sup_fgFLOAT32);
#endif
}
void flgr1d_arith_sup_shift_left_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
#if defined(__SSE2__)
  flgr1d_arith_sup_shift_left_fast_fgFLOAT64(datdest,data1,left_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgFLOAT64,flgr_defop_sup_fgFLOAT64);
#endif
}
////////////////////////////////////////////////////////////////////////////
/*! Compute Sup between data1 and data1 shifted on the left by left_shift_size elements
 *  @param datdest : pointer to FLGR_Data1D
 *  @param data1 : pointer to FLGR_Data1D
 *  @param left_shift_size : integer
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_arith_sup_shift_left(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (data1==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(left_shift_size<0) {
    POST_ERROR("shift size must be > 0\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if((ret = flgr1d_is_data_same_attributes(datdest,data1,__FUNCTION__)) != FLGR_RET_OK) return ret;

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_arith_sup_shift_left,datdest,data1,left_shift_size);

}






void flgr1d_arith_inf_shift_right_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
  if((right_shift_size==1) &&(datdest->spp==1)) {
    flgr1d_arith_inf_shift_1_right_fast_fgBIT(datdest,data1);
  }else {
    FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgBIT,flgr_defop_inf_fgBIT);
  }
}
void flgr1d_arith_inf_shift_right_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
#if defined(__SSE2__) || defined(__SSE__)
  flgr1d_arith_inf_shift_right_fast_fgUINT8(datdest,data1,right_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgUINT8,flgr_defop_inf_fgUINT8); 
#endif
}
void flgr1d_arith_inf_shift_right_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgUINT16,flgr_defop_inf_fgUINT16); 
}
void flgr1d_arith_inf_shift_right_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgUINT32,flgr_defop_inf_fgUINT32); 
}
void flgr1d_arith_inf_shift_right_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgINT8,flgr_defop_inf_fgINT8); 
}
void flgr1d_arith_inf_shift_right_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
#if defined(__SSE2__) || defined(__SSE__)
  flgr1d_arith_inf_shift_right_fast_fgINT16(datdest,data1,right_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgINT16,flgr_defop_inf_fgINT16); 
#endif
}
void flgr1d_arith_inf_shift_right_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgINT32,flgr_defop_inf_fgINT32); 
}
void flgr1d_arith_inf_shift_right_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
#if defined(__SSE__)
  flgr1d_arith_inf_shift_right_fast_fgFLOAT32(datdest,data1,right_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgFLOAT32,flgr_defop_inf_fgFLOAT32); 
#endif
}
void flgr1d_arith_inf_shift_right_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
#if defined(__SSE2__) 
  flgr1d_arith_inf_shift_right_fast_fgFLOAT64(datdest,data1,right_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_RIGHT(fgFLOAT64,flgr_defop_inf_fgFLOAT64); 
#endif
}

////////////////////////////////////////////////////////////////////////////
/*! Compute Inf between data1 and data1 shifted on the right by right_shift_size elements
 *  @param datdest : pointer to FLGR_Data1D
 *  @param data1 : pointer to FLGR_Data1D
 *  @param right_shift_size : integer
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_arith_inf_shift_right(FLGR_Data1D *datdest, FLGR_Data1D *data1, int right_shift_size) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (data1==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(right_shift_size<0) {
    POST_ERROR("shift size must be > 0\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if((ret = flgr1d_is_data_same_attributes(datdest,data1,__FUNCTION__)) != FLGR_RET_OK) return ret;

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_arith_inf_shift_right,datdest,data1,right_shift_size);

}





void flgr1d_arith_inf_shift_left_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
  if((left_shift_size==1) && (datdest->spp==1)) {
    flgr1d_arith_inf_shift_1_left_fast_fgBIT(datdest,data1);
  }else {
    FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgBIT,flgr_defop_inf_fgBIT);
  }
}
void flgr1d_arith_inf_shift_left_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
#if defined(__SSE2__) || defined(__SSE__)
  flgr1d_arith_inf_shift_left_fast_fgUINT8(datdest,data1,left_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgUINT8,flgr_defop_inf_fgUINT8);
#endif
}
void flgr1d_arith_inf_shift_left_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgUINT16,flgr_defop_inf_fgUINT16);
}
void flgr1d_arith_inf_shift_left_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgUINT32,flgr_defop_inf_fgUINT32);
}
void flgr1d_arith_inf_shift_left_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgINT8,flgr_defop_inf_fgINT8);
}
void flgr1d_arith_inf_shift_left_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
#if defined(__SSE2__) || defined(__SSE__)
  flgr1d_arith_inf_shift_left_fast_fgINT16(datdest,data1,left_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgINT16,flgr_defop_inf_fgINT16);
#endif
}
void flgr1d_arith_inf_shift_left_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgINT32,flgr_defop_inf_fgINT32);
}
void flgr1d_arith_inf_shift_left_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
#if defined(__SSE__)
  flgr1d_arith_inf_shift_left_fast_fgFLOAT32(datdest,data1,left_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgFLOAT32,flgr_defop_inf_fgFLOAT32);
#endif
}
void flgr1d_arith_inf_shift_left_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
#if defined(__SSE2__)
  flgr1d_arith_inf_shift_left_fast_fgFLOAT64(datdest,data1,left_shift_size);
#else
  FLGR_MACRO_1D_ARITH_OP_SHIFT_LEFT(fgFLOAT64,flgr_defop_inf_fgFLOAT64);
#endif
}
////////////////////////////////////////////////////////////////////////////
/*! Compute Inf between data1 and data1 shifted on the left by left_shift_size elements
 *  @param datdest : pointer to FLGR_Data1D
 *  @param data1 : pointer to FLGR_Data1D
 *  @param left_shift_size : integer
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_arith_inf_shift_left(FLGR_Data1D *datdest, FLGR_Data1D *data1, int left_shift_size) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (data1==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(left_shift_size<0) {
    POST_ERROR("shift size must be > 0\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if((ret = flgr1d_is_data_same_attributes(datdest,data1,__FUNCTION__)) != FLGR_RET_OK) return ret;

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_arith_inf_shift_left,datdest,data1,left_shift_size);

}

